// 版权所有2011 Go作者。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 包颜色实现基本颜色库。
package color

// 颜色可以将自身转换为每个通道RGBA的16位alpha预乘。
// 转换可能有损。
type Color interface {
	// RGBA返回颜色的alpha预乘红色、绿色、蓝色和alpha值
	// 。每个值都在[0，0xffff]范围内，但由一个uint32表示
	// 因此，与混合因子相乘到0xffff将不会导致
	// 溢出。
	// 
	// 阿尔法预乘颜色分量c已按阿尔法（a）缩放，
	// 因此具有有效值0<=c<=a。
	RGBA() (r, g, b, a uint32)
}

// RGBA表示传统的32位alpha预乘颜色，红色、绿色、蓝色和alpha各有8位
// 。
// 
// 阿尔法预乘颜色分量C已按阿尔法（A）缩放，因此
// 具有有效值0<=C<=A。
type RGBA struct {
	R, G, B, A uint8
}

func (c RGBA) RGBA() (r, g, b, a uint32) {
	r = uint32(c.R)
	r |= r << 8
	g = uint32(c.G)
	g |= g << 8
	b = uint32(c.B)
	b |= b << 8
	a = uint32(c.A)
	a |= a << 8
	return
}

// RGBA64表示64位阿尔法预乘颜色，具有16位用于
// 红色、绿色、蓝色和阿尔法。
// 
// 阿尔法预乘颜色分量C已按阿尔法（A）缩放，因此
// 具有有效值0<=C<=A。
type RGBA64 struct {
	R, G, B, A uint16
}

func (c RGBA64) RGBA() (r, g, b, a uint32) {
	return uint32(c.R), uint32(c.G), uint32(c.B), uint32(c.A)
}

// NRGBA表示非阿尔法预乘32位颜色。
type NRGBA struct {
	R, G, B, A uint8
}

func (c NRGBA) RGBA() (r, g, b, a uint32) {
	r = uint32(c.R)
	r |= r << 8
	r *= uint32(c.A)
	r /= 0xff
	g = uint32(c.G)
	g |= g << 8
	g *= uint32(c.A)
	g /= 0xff
	b = uint32(c.B)
	b |= b << 8
	b *= uint32(c.A)
	b /= 0xff
	a = uint32(c.A)
	a |= a << 8
	return
}

// NRGBA64表示非alpha预乘64位颜色，
// 红、绿、蓝和alpha各有16位。
type NRGBA64 struct {
	R, G, B, A uint16
}

func (c NRGBA64) RGBA() (r, g, b, a uint32) {
	r = uint32(c.R)
	r *= uint32(c.A)
	r /= 0xffff
	g = uint32(c.G)
	g *= uint32(c.A)
	g /= 0xffff
	b = uint32(c.B)
	b *= uint32(c.A)
	b /= 0xffff
	a = uint32(c.A)
	return
}

// Alpha表示8位Alpha颜色。
type Alpha struct {
	A uint8
}

func (c Alpha) RGBA() (r, g, b, a uint32) {
	a = uint32(c.A)
	a |= a << 8
	return a, a, a, a
}

// Alpha16表示16位alpha颜色。
type Alpha16 struct {
	A uint16
}

func (c Alpha16) RGBA() (r, g, b, a uint32) {
	a = uint32(c.A)
	return a, a, a, a
}

// 灰色表示8位灰度颜色。
type Gray struct {
	Y uint8
}

func (c Gray) RGBA() (r, g, b, a uint32) {
	y := uint32(c.Y)
	y |= y << 8
	return y, y, y, 0xffff
}

// 灰度16表示16位灰度颜色。
type Gray16 struct {
	Y uint16
}

func (c Gray16) RGBA() (r, g, b, a uint32) {
	y := uint32(c.Y)
	return y, y, y, 0xffff
}

// 模型可以将任何颜色从自己的颜色模型转换为一种颜色。转换
// 可能有损。
type Model interface {
	Convert(c Color) Color
}

// ModelFunc返回一个调用f来实现转换的模型。
func ModelFunc(f func(Color) Color) Model {
	// 注意：使用*modelFunc作为实现
	// 意味着调用方仍然可以使用比较
	// 类似于m==RGBAModel。如果
	// 我们直接使用func值，这是不可能的，因为funcs 
	// 不再具有可比性。
	return &modelFunc{f}
}

type modelFunc struct {
	f func(Color) Color
}

func (m *modelFunc) Convert(c Color) Color {
	return m.f(c)
}

// 标准颜色类型的型号。
var (
	RGBAModel    Model = ModelFunc(rgbaModel)
	RGBA64Model  Model = ModelFunc(rgba64Model)
	NRGBAModel   Model = ModelFunc(nrgbaModel)
	NRGBA64Model Model = ModelFunc(nrgba64Model)
	AlphaModel   Model = ModelFunc(alphaModel)
	Alpha16Model Model = ModelFunc(alpha16Model)
	GrayModel    Model = ModelFunc(grayModel)
	Gray16Model  Model = ModelFunc(gray16Model)
)

func rgbaModel(c Color) Color {
	if _, ok := c.(RGBA); ok {
		return c
	}
	r, g, b, a := c.RGBA()
	return RGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
}

func rgba64Model(c Color) Color {
	if _, ok := c.(RGBA64); ok {
		return c
	}
	r, g, b, a := c.RGBA()
	return RGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
}

func nrgbaModel(c Color) Color {
	if _, ok := c.(NRGBA); ok {
		return c
	}
	r, g, b, a := c.RGBA()
	if a == 0xffff {
		return NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), 0xff}
	}
	if a == 0 {
		return NRGBA{0, 0, 0, 0}
	}
	// 因为Color.RGBA返回一个alpha预乘颜色，所以我们应该让r<=a&&g<=a&&b<=a。
	r = (r * 0xffff) / a
	g = (g * 0xffff) / a
	b = (b * 0xffff) / a
	return NRGBA{uint8(r >> 8), uint8(g >> 8), uint8(b >> 8), uint8(a >> 8)}
}

func nrgba64Model(c Color) Color {
	if _, ok := c.(NRGBA64); ok {
		return c
	}
	r, g, b, a := c.RGBA()
	if a == 0xffff {
		return NRGBA64{uint16(r), uint16(g), uint16(b), 0xffff}
	}
	if a == 0 {
		return NRGBA64{0, 0, 0, 0}
	}
	// 因为Color.RGBA返回一个alpha预乘颜色，所以我们应该让r<=a&&g<=a&&b<=a。
	r = (r * 0xffff) / a
	g = (g * 0xffff) / a
	b = (b * 0xffff) / a
	return NRGBA64{uint16(r), uint16(g), uint16(b), uint16(a)}
}

func alphaModel(c Color) Color {
	if _, ok := c.(Alpha); ok {
		return c
	}
	_, _, _, a := c.RGBA()
	return Alpha{uint8(a >> 8)}
}

func alpha16Model(c Color) Color {
	if _, ok := c.(Alpha16); ok {
		return c
	}
	_, _, _, a := c.RGBA()
	return Alpha16{uint16(a)}
}

func grayModel(c Color) Color {
	if _, ok := c.(Gray); ok {
		return c
	}
	r, g, b, _ := c.RGBA()

	// 这些系数（分数0.299、0.587和0.114）与JFIF规范中给出并由func RGBToYCbCr在
	// ycbcr.go中使用的系数相同。注意19595+38470+7471等于65536。
	// 
	// /24是16+8。16与RGBToYCbCr中使用的相同。8是
	// 因为返回值是8位颜色，而不是16位颜色。
	y := (19595*r + 38470*g + 7471*b + 1<<15) >> 24

	return Gray{uint8(y)}
}

func gray16Model(c Color) Color {
	if _, ok := c.(Gray16); ok {
		return c
	}
	r, g, b, _ := c.RGBA()

	// 这些系数（分数0.299、0.587和0.114）与JFIF规范中给出并由func RGBToYCbCr在
	// ycbcr.go中使用的系数相同。注意19595+38470+7471等于65536。
	y := (19595*r + 38470*g + 7471*b + 1<<15) >> 16

	return Gray16{uint16(y)}
}

// 调色板是一种颜色调色板。
type Palette []Color

// Convert返回欧氏R、G、B空间中最接近c的调色板颜色。
func (p Palette) Convert(c Color) Color {
	if len(p) == 0 {
		return nil
	}
	return p[p.Index(c)]
}

// Index返回欧几里德公式中最接近c的调色板颜色的索引
// R，G，B，A空间。
func (p Palette) Index(c Color) int {
	// 此计算的批处理版本位于image/draw/draw.go中。

	cr, cg, cb, ca := c.RGBA()
	ret, bestSum := 0, uint32(1<<32-1)
	for i, v := range p {
		vr, vg, vb, va := v.RGBA()
		sum := sqDiff(cr, vr) + sqDiff(cg, vg) + sqDiff(cb, vb) + sqDiff(ca, va)
		if sum < bestSum {
			if sum == 0 {
				return i
			}
			ret, bestSum = i, sum
		}
	}
	return ret
}

// sqDiff返回x和y的平方差，移动2，这样
// 添加其中的四个不会溢出uint32。假设x和y都在[0，0xffff]范围内。
func sqDiff(x, y uint32) uint32 {
	// 此函数的规范代码如下所示：
	// 
	// var d uint32 
	// if x>y{
	// /d=x-y 
	// /}else{
	// /d=y-x 
	// /}返回（d*d）>>2 
	// 
	// 语言规范保证无符号整数
	// 与溢出/环绕有关的值运算的以下属性：
	// 
	// />对于无符号整数值，运算+，-，*，和<<是
	// />计算的模2n，其中n是无符号
	// />整数类型的位宽度。不严格地说，这些无符号整数操作是
	// />溢出时丢弃高位，程序可能依赖于“环绕
	// />”。
	// 
	// 考虑到这些属性以及此函数是在热路径（x，y循环）中调用的
	// 这一事实，它被简化为下面的代码
	// 稍微快一点。有关正确性检查，请参阅TestSqDiff。
	d := x - y
	return (d * d) >> 2
}

// 标准颜色。
var (
	Black       = Gray16{0}
	White       = Gray16{0xffff}
	Transparent = Alpha16{0}
	Opaque      = Alpha16{0xffff}
)
